package tk.mynoteapp.dev.wechat.pay.common;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import org.springframework.web.bind.annotation.RequestMethod;
import tk.mynoteapp.dev.wechat.pay.enums.AuthType;
import tk.mynoteapp.dev.wechat.pay.enums.WxApiType;
import tk.mynoteapp.dev.wechat.pay.enums.WxDomain;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付相关接口调用工具类
 */
public class WxPayApi {

    /**
     * 微信支付 V3 版接口统一执行入口
     *
     * @param method       {@link RequestMethod} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain} 来获取 请求域名地址
     * @param urlSuffix    可通过 {@link WxApiType} 来获取，请求路径，URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号，接口中包含敏感信息时必传
     * @param keyPath      apiclient_key.pem 商户API私钥路径
     * @param body         接口请求参数
     * @param nonceStr     随机字符库
     * @param timestamp    时间戳
     * @param authType     认证类型
     * @param file         文件
     * @return {@link PayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static PayHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix,
                                     String mchId, String serialNo, String platSerialNo,
                                     String keyPath, String body, String nonceStr, long timestamp,
                                     String authType, File file) throws Exception {
        // 构建构造签名串 Authorization
        String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo,
                keyPath, body, nonceStr, timestamp, authType);

        if (StrUtil.isEmpty(platSerialNo)) {
            platSerialNo = serialNo;
        }

        if (method == RequestMethod.GET) {
            return get(urlPrefix.concat(urlSuffix), authorization, platSerialNo, null);
        } else if (method == RequestMethod.POST) {
            return post(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        }
        return null;
    }

    /**
     * 微信支付 V3 版接口统一执行入口
     *
     * @param method       {@link RequestMethod} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain} 来获取 接口域名地址
     * @param urlSuffix    可通过 {@link WxApiType} 来获取，接口请求路径，URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 商户API私钥路径
     * @param body         接口请求参数
     * @return {@link PayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static PayHttpResponse v3(RequestMethod method, String urlPrefix,
                                     String urlSuffix, String mchId,
                                     String serialNo, String platSerialNo,
                                     String keyPath, String body) throws Exception {
        long timestamp = PayKit.generateTimestamp(); // 系统当前时间戳
        String authType = AuthType.WECHATPAY2.getType(); // 认证类型
        String nonceStr = PayKit.generateStr(); // 随机串
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo,
                keyPath, body, nonceStr, timestamp, authType, null);
    }

    /**
     * get 请求
     *
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param params        请求参数
     * @return {@link PayHttpResponse}    请求返回的结果
     */
    public static PayHttpResponse get(String url, String authorization, String serialNumber,
                                      Map<String, Object> params) {
        HttpResponse httpResponse = HttpRequest.get(url)
                .addHeaders(getHeaders(authorization, serialNumber))
                .form(params)
                .execute();
        PayHttpResponse response = new PayHttpResponse();
        response.setBody(httpResponse.body());
        response.setStatus(httpResponse.getStatus());
        response.setHeaders(httpResponse.headers());
        return response;
    }

    /**
     * post 请求
     *
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @return {@link PayHttpResponse}    请求返回的结果
     */
    public static PayHttpResponse post(String url, String authorization, String serialNumber, String data) {
        HttpResponse httpResponse = HttpRequest.post(url)
                .addHeaders(getHeaders(authorization, serialNumber))
                .body(data)
                .execute();

        PayHttpResponse response = new PayHttpResponse();
        response.setBody(httpResponse.body());
        response.setStatus(httpResponse.getStatus());
        response.setHeaders(httpResponse.headers());
        return response;
    }

//    private static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version");
//    private static final String VERSION = System.getProperty("java.version");

//    /**
//     *
//     * @param authorization
//     * @return
//     */
//    public static Map<String, String> getBaseHeaders(String authorization) {
//        String userAgent = String.format(
//                "WeChatPay-YX-HttpClient/%s (%s) Java/%s",
//                WxPayApi.class.getPackage().getImplementationVersion(),
//                OS,
//                VERSION == null ? "Unknown" : VERSION);
//
//        Map<String, String> headers = new HashMap<>(5);
//        headers.put("Accept", ContentType.JSON.toString());
//        headers.put("Authorization", authorization);
//        headers.put("User-Agent", userAgent);
//        return headers;
//    }

    /**
     * 设置HTTP头
     * @param authorization 签名串
     * @param serialNumber 商户API或微信平台证书序列号
     * @return 返回请求头
     */
    public static Map<String, String> getHeaders(String authorization, String serialNumber) {
        Map<String, String> headers = new HashMap<>(4);
        headers.put("Accept", ContentType.JSON.toString());
        headers.put("Authorization", authorization);
        headers.put("Content-Type", ContentType.JSON.toString());
        if (StrUtil.isNotEmpty(serialNumber)) {
            headers.put("Wechatpay-Serial", serialNumber);
        }
        return headers;
    }
}
